package com.bean;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Pro collection utils
 *
 * @description: 集合工具
 * @author: cyj
 * @date 2022 -02-21 18:32:07
 *
 *
 */
public class ProCollectionUtils {

    /**
     * List to map map list转map
     *
     * @param <T>    parameter
     * @param <R>    parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @return the map
     */
    public static <T, R> Map<R, T> listToMap(List<T> source, Function<T, R> key) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, Function.identity(), (o1, o2) -> o1));
    }

    /**
     * List to map map list转map
     *
     * @param <T>    parameter
     * @param <R>    parameter
     * @param <U>    parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @param value  value 返回map Value值
     * @return the map
     */
    public static <T, R, U> Map<R, U> listToMap(List<T> source, Function<T, R> key, Function<T, U> value) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, value, (o1, o2) -> o1));
    }

    /**
     * List to map map list转map
     *
     * @param <T>           parameter
     * @param <R>           parameter
     * @param <U>           parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @param value  value 返回map Value值
     * @param mergeFunction merge function  新老替换逻辑
     * @return the map
     */
    public static <T, R, U> Map<R, U> listToMap(List<T> source, Function<T, R> key, Function<T, U> value, BinaryOperator<U> mergeFunction) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, value, mergeFunction));
    }

    /****************************************************** set 操作 *************************************/
    /**
     * set to map map list转map
     *
     * @param <T>    parameter
     * @param <R>    parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @return the map
     */
    public static <T, R> Map<R, T> setToMap(Set<T> source, Function<T, R> key) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, Function.identity(), (o1, o2) -> o1));
    }

    /**
     * set to map map list转map
     *
     * @param <T>    parameter
     * @param <R>    parameter
     * @param <U>    parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @param value  value 返回map Value值
     * @return the map
     */
    public static <T, R, U> Map<R, U> setToMap(Set<T> source, Function<T, R> key, Function<T, U> value) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, value, (o1, o2) -> o1));
    }

    /**
     * set to map map list转map
     *
     * @param <T>           parameter
     * @param <R>           parameter
     * @param <U>           parameter
     * @param source source 源数据
     * @param key    key 返回map Key值
     * @param value  value 返回map Value值
     * @param mergeFunction merge function  新老替换逻辑
     * @return the map
     */
    public static <T, R, U> Map<R, U> setToMap(Set<T> source, Function<T, R> key, Function<T, U> value, BinaryOperator<U> mergeFunction) {
        if (null == source) {
            return new HashMap<>();
        }
        return source.stream().collect(Collectors.toMap(key, value, mergeFunction));
    }

    /**
     * List partition list 分区
     *
     * @param <T>        parameter
     * @param source     source 源
     * @param batchCount batch count 体型
     * @return the list
     */
    public static <T> List<List<T>> listPartition(List<T> source, Integer batchCount) {
        List<List<T>> result = new ArrayList<>();
        if (null == source) {
            return result;
        }
        IntStream.range(0, source.size()).forEach(i -> {
            List<T> resultTemp = null;
            if (i % batchCount == 0) {
                resultTemp = new ArrayList<>(batchCount);
                result.add(resultTemp);
            } else {
                resultTemp = result.get(i / batchCount);
            }
            resultTemp.add(source.get(i));
        });
        return result;
    }

    /**
     * set partition set 分区
     *
     * @param <T>        parameter
     * @param source     source 源
     * @param batchCount batch count 体型
     * @return the list
     */
    public static <T> List<List<T>> setPartition(Set<T> source, Integer batchCount) {
        List<List<T>> result = new ArrayList<>();
        if (null == source) {
            return result;
        }
        return listPartition(new ArrayList<>(source), batchCount);
    }

}
